package com.dns.test.client;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

import com.dns.message.DNS_Message;
import com.dns.util.Constants;


public class DNSClient {

	public static String primaryServerIP = "127.0.0.1";
	public static String primaryServerPort = "9000";
	public static String secondaryServerIP_Edu = "127.0.0.1";
	public static String secondaryServerPort_Edu = "8284";
	public static String secondaryServerIP_Org = "127.0.0.1";
	public static String secondaryServerPort_Org = "8285";
	public static String secondaryServerIP_Com = "127.0.0.1";
	public static String secondaryServerPort_Com = "8286";	
	public static int clientPort = 8000;
	public static String clientIP = "127.0.0.1";
	public static DatagramSocket clientSocket;
	public static int numInputs = 45;
	public static int numThreads = 5;
	public static int scenarios = 4;
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		try
		{			
			//System.out.println("Listening for Messages At PORT: "+Integer.toString(clientPort));
			
			clientSocket = new DatagramSocket(clientPort);
			
			//MessageReceiverThread receiverThread = new MessageReceiverThread();
			//receiverThread.run();
	
			int scenarioId = Integer.parseInt(args[0]);	
			
			if(scenarioId <= scenarios)
				runScenario(scenarioId);
			else
				fireMessages();
		
			//receiverThread.join();
			
			clientSocket.close();
			
		}catch(Exception exception)
		{ 
			System.err.println("Exception @DNSClient: "+exception.getMessage());
		}
	}

	public static void runScenario(int scenarioId) throws SocketException, InterruptedException
	{
		MessageSenderThread [] threads = new MessageSenderThread[numThreads];
		
		for(int index = 0; index < 3; ++index)
		{
			threads[index] = new MessageSenderThread();							
		}
		
		for(int index = 0; index < 3; ++index)
		{
			int startIndex = threadStartIndex(index, scenarioId);
			int endIndex = threadEndIndex(index, scenarioId);
					
			threads[index].run(startIndex, endIndex, scenarioId);							
		}			
		
		for(int index = 0; index < 3; ++index)
			threads[index].join();		
		
	}
	
	public static int threadStartIndex(int threadId, int scenarioId)
	{
		switch(scenarioId)
		{
		case 1: switch(threadId)
				{
					case 0:	return 0;
					case 1: return 2;
					case 2: return 4;
				}
				break;
		case 2: switch(threadId)
				{
					case 0:	return 0;
					case 1: return 2;
					case 2: return 4;
				}
				break;
		case 3: switch(threadId)
				{
					case 0:	return 0;
					case 1: return 2;
					case 2: return 4;
				}
				break;
		case 4: switch(threadId)
				{
					case 0:	return 0;
					case 1: return 1;
					case 2: return 2;
				}
				break;				
		default:
				return 0;
		}
		
		return 0;
	}

	public static int threadEndIndex(int threadId, int scenarioId)
	{
		switch(scenarioId)
		{
		case 1: switch(threadId)
				{
					case 0:	return 1;
					case 1: return 3;
					case 2: return 5;
				}
				break;
		case 2: switch(threadId)
				{
					case 0:	return 1;
					case 1: return 3;
					case 2: return 5;
				}
				break;
		case 3: switch(threadId)
				{
					case 0:	return 1;
					case 1: return 3;
					case 2: return 5;
				}
				break;
		case 4: switch(threadId)
				{
					case 0:	return 0;
					case 1: return 1;
					case 2: return 2;
				}
				break;				
		default:
				return 0;
		}
		
		return 0;
	}
	
	public static void fireMessages() throws SocketException, InterruptedException
	{
		MessageSenderThread [] threads = new MessageSenderThread[numThreads];
		
		for(int index = 0; index < numThreads; ++index)
		{
			threads[index] = new MessageSenderThread();							
		}

		int workPerThread = (numInputs/numThreads);
		
		for(int index = 0; index < numThreads; ++index)
		{
			int startIndex = (index*workPerThread);
			int endIndex = 0;
			if(index == (numThreads - 1))
					endIndex = numInputs - 1;
			else
				endIndex = startIndex + workPerThread - 1;
					
			threads[index].run(startIndex, endIndex, (DNSClient.scenarios+1));							
		}			
		
		for(int index = 0; index < numThreads; ++index)
			threads[index].join();		
	}
	
	public static void sendMessage(String serverIP, int serverPort, DNS_Message msg) throws SocketException
	{
		printMessage(msg);
		
		DatagramPacket sendPacket;
		byte []buff = new byte[Constants.DATA_BUFFER_SIZE];
		
		
		ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
		ObjectOutputStream objectOut;
		try {
			objectOut = new ObjectOutputStream(byteOut);
			objectOut.writeObject(msg);
			buff =byteOut.toByteArray();
			sendPacket = new DatagramPacket(buff, buff.length, InetAddress.getByName(serverIP), serverPort);
			System.out.println("Sending Message: To IP: "+serverIP+" PORT: "+serverPort+"\n");
			clientSocket.send(sendPacket);
		} catch (IOException e) {
			System.out.println(" : Exception while creating the serializing or writing the DNS_Message object");
			e.printStackTrace();
		}
		finally{
			byteOut=null;
			objectOut=null;
			buff=null;			
		}		
	}
	
	public static void printMessage(DNS_Message msg)
	{
		String source = msg.getSource();
		
		int msgType = msg.getMsgType();
		String msgTypeString = new String();
		switch(msgType)
		{
		case 0: msgTypeString = "MSG_INQUIRY";
				break;
		case 1: msgTypeString = "MSG_UPDATE";
				break;		
		case 2: msgTypeString = "MSG_RESPONSE";
				break;		
		case 3: msgTypeString = "MSG_REGISTER";
				break;
		default:
				msgTypeString = "INVALIDE MSG TYPE";
				break;
		}
		
		String domainName = msg.getDomainName();
		
		String ip = msg.getIp_address();
		String result;
		if(msg.getResult() == 1)			
		   result = "SUCCESS";
		else
			result = "FAILURE";
		
		boolean messageSent = false;
		if(source.equals(Constants.CLIENT))
			messageSent = true;
		
		if(messageSent)
			System.out.println("--------------------Message Sent-----------------------");
		else
			System.out.println("--------------------Message Received-------------------");
					
		System.out.println("MSG SOURCE : "+source+
						   "\nMSG TYPE   : "+msgTypeString+					
						   "\nDOMAIN NAME: "+domainName+
						   "\nIP ADDRESS : "+ip);
		if(!messageSent)
		System.out.println("RESULT	   : "+result);	
						  
		
		System.out.println("--------------------------------------------------------");	
	}	
	
}
